package parser;
import java.util.*;
import java.io.*; 
import antlr.RecognitionException;

/** Need to rework Local variable logic to work properly in two passes 
 *  First pass identify all used and bound variables
 *  If variable is used in a nested scope, forces frame onto stack all variables
 *  become DEREF as frame is heap allocated.  */

public class FunctionScope extends LocalScope {

    static final int ESCAPES = 1024;
    static final int CLOSURE = 2048;
    
    FunctionScope(List<Parameter2> parameters, Scope enclosing) throws RecognitionException {
        super(enclosing instanceof FunctionScope ? enclosing : null);
        // Is function name in the scope of the function?
        indices = new HashMap<Integer, Integer>();
        Set<Integer> pNames = new HashSet<Integer>();
        for (Parameter2 p : parameters) {
            if (pNames.contains(p.getName()))
                throw new RecognitionException("Repeat name in parameters");
            locals.set(p.getName());
            pNames.add(p.getName());
        }
        this.parameters = parameters;
    }
 
    Map<Integer, Integer> indices;
    int tempIndex;
    List<Parameter2> parameters;
    
    Type variable(int name) {
        if (!closed)
            close();
        Integer i = indices.get(name); 
        if (i == null) {
            return escape(name, 0);
        } else { 
            return new FastLocal(i);
        }
    }
    
    Type escape(int name, int depth) {
        Integer i = indices.get(name);
        if (i != null) {
            return new DeRef(i, depth);
        } else if (enclosing != null) {
            return enclosing.escape(name, depth + 1);
        } else {
            return new GlobalVar(name);
        }
    }

    boolean closed;
    
    int[] getLocals() {
        if (!closed)
            close();
        int size = locals.cardinality();
        int[] names = new int[size];
        for(int i= locals.nextSetBit(0); i>=0; i=locals.nextSetBit(i+1)) {
            if (!indices.containsKey(i)) {
                throw new Error("Indices does not contain key: " + i);   
            }
            names[indices.get(i)] = i;
        }
        return names;
    }
    
    void close() {
        if (closed)
            return;
        closed = true;
        if (enclosing != null) {
            int name_0 = NameTable.getIndex("0");
            indices.put(name_0, 0);
            locals.set(name_0);
        }
        for (Parameter2 p : parameters) {
            indices.put(p.getName(), indices.size());
        }
        for(int i= locals.nextSetBit(0); i>=0; i=locals.nextSetBit(i+1)) {
            used.set(i, false);
            if (!indices.containsKey(i)) {
                indices.put(i, indices.size());
            }
        }
    }
    
    boolean is_closure() {
        return enclosing != null; 
    }
     
}
